package com.jeffpalm.pandoralastfm;

import net.roarsoftware.lastfm.Result;

/**
 * This is the bridge between Pandora and LastFm with no dependency on GUI
 * stuff.
 */
final class PandoraLastFmBridge {

  private final Pandora pandora;
  private final LastFm lastFm;

  PandoraLastFmBridge(Pandora pandora, LastFm lastFm) {
    this.pandora = pandora;
    this.lastFm = lastFm;
  }

  PandoraLastFmBridge(String username) {
    // XXX: Hack
    this(PandoraImpl.getInstance(), LastFm.getInstance(username == null ? "spudtrooper" : username));
  }

  // ----------------------------------------------------
  // Interface
  // ----------------------------------------------------

  /**
   * The result returned from all interface operations.
   */
  interface BridgeResult {
    /**
     * Returns the appropriate message, returning {@link #getErrorMessage()} if
     * {@link #isSuccessful()} is <code>false</code>, otherwise returns
     * {@Link #getSuccessMessage()}.
     * 
     * @return the appropriate message, returning {@link #getErrorMessage()} if
     *         {@link #isSuccessful()} is <code>false</code>, otherwise
     *         returns {@Link #getSuccessMessage()}
     */
    String getMessage();

    /**
     * Returns the error message that would show upon a failure. This could be
     * non-<code>null</code> even if {@link #isSuccessful()} is
     * <code>true</code>.
     * 
     * @return the error message that would show upon a failure
     */
    String getErrorMessage();

    /**
     * Returns the success message that would show upon a success. This could be
     * non-<code>null</code> even if {@link #isSuccessful()} is
     * <code>false</code>.
     * 
     * @return the success message that would show upon a success
     */
    String getSuccessMessage();

    /**
     * Returns whether this operation was succesful.
     * 
     * @return whether this operation was succesful
     */
    boolean isSuccessful();
  }

  private abstract static class AbstractBridgeResult implements BridgeResult {
    public final String getMessage() {
      return isSuccessful() ? getSuccessMessage() : getErrorMessage();
    }
  }

  private final static class SuccessfulBridgeResult extends AbstractBridgeResult {
    private final String msg;

    public SuccessfulBridgeResult(String msg) {
      this.msg = msg;
    }

    public String getSuccessMessage() {
      return msg;
    }

    public String getErrorMessage() {
      return null;
    }

    public boolean isSuccessful() {
      return true;
    }
  }

  /**
   * Returns the result of <em>up</em>ing a Pandora track and then adding
   * that track to LastFM. This cannot be <code>null</code>.
   * 
   * @return the result of <em>up</em>ing a Pandora track and then adding
   *         that track to LastFM
   */
  public BridgeResult up() {
    getPandora().thumbsUp();
    return addCurrentTrackToLastFm(getPandora().getCurrentArtist(), getPandora().getCurrentTrack());
  }

  /**
   * Returns the result of <em>down</em>ing a Pandora track. This cannot be
   * <code>null</code>.
   * 
   * @return the result of <em>down</em>ing a Pandora track
   */
  public BridgeResult down() {
    return new SuccessfulBridgeResult(getPandora().thumbsDown());
  }

  /**
   * Returns the result of <em>next</em>ing a Pandora track. This cannot be
   * <code>null</code>.
   * 
   * @return the result of <em>next</em>ing a Pandora track
   */
  public BridgeResult next() {
    return new SuccessfulBridgeResult(getPandora().nextTrack());
  }

  /**
   * Returns the result of adding that track to LastFM. This cannot be
   * <code>null</code>.
   * 
   * @return the result of adding that track to LastFM
   */
  public BridgeResult addCurrentTrackToLastFm(final String artist, final String track) {
    final Result r = getLastFm().addTrackToDefaultPlaylist(artist, track);
    BridgeResult res = new AbstractBridgeResult() {
      public String getErrorMessage() {
        return r.getErrorMessage();
      }

      public String getSuccessMessage() {
        return "Added " + track + " by " + artist;
      }

      public boolean isSuccessful() {
        return r.isSuccessful();
      }
    };
    return res;
  }

  // ----------------------------------------------------
  // Composite interface
  // ----------------------------------------------------

  final Pandora getPandora() {
    return pandora;
  }

  final LastFm getLastFm() {
    return lastFm;
  }
}